/*!
 * \file RdWrLock.h
 * \brief Read write lock.
 * \author Nus
 * \date 2008/03/15 09:53
 */

#ifndef __RDWRLOCK_H__
#define __RDWRLOCK_H__

#include "Debug.h"
#include "MutualExcl.h"

/*!
 * \class RdWrLock
 * \brief Read write lock.
 *
 * Use this to lock your data for writing or locking.
 */
class RdWrLock : public MutualExcl
{
public:
  //! \brief Lock type.
  enum eLockType {
    READ_LOCK = 0,
    WRITE_LOCK,
    TRY_READ_LOCK,
    TRY_WRITE_LOCK,
  };

  //! \brief Default constructor.
  RdWrLock();
  
  //! \brief Default destructor.
  virtual ~RdWrLock();

  //! \brief Lock.
  virtual s32 lock(eLockType type) {
    ASSERT_C(mStatus == 0);
    switch(type) {
    case READ_LOCK:
      return readLock();
    case WRITE_LOCK:
      return writeLock();
    case TRY_READ_LOCK:
      return readTryLock();
    case TRY_WRITE_LOCK:
      return writeTryLock();
    default:
      ASSERT_EX(false, "Unknown lock type\n");
    }
    return EC_CRITICAL_ERROR;
  }
  
  //! \brief Lock for reading.
  virtual s32 readLock(void) {
    ASSERT_C(mStatus == 0);
    return pthread_rwlock_rdlock(&mRdWrLock);
  }

  //! \brief Lock for writing.
  virtual s32 writeLock(void) {
    ASSERT_C(mStatus == 0);
    return pthread_rwlock_rdlock(&mRdWrLock);
  }

  //! \brief Try lock for reading.
  virtual s32 readTryLock(void) {
    ASSERT_C(mStatus == 0);
    return pthread_rwlock_tryrdlock(&mRdWrLock);
  }

  //! \brief Try lock for writing.
  virtual s32 writeTryLock(void) {
    ASSERT_C(mStatus == 0);
    return pthread_rwlock_trywrlock(&mRdWrLock);
  }

  //! \brief Unlock.
  virtual s32 unlock(void) {
    ASSERT_C(mStatus == 0);
    return pthread_rwlock_unlock(&mRdWrLock);
  }

protected:
  pthread_rwlock_t mRdWrLock;     //!< Read write lock.

private:
  // None...

};



/*!
 * \class AutoReadLock
 * \brief Automatically lock for reading.
 */
class AutoReadLock
{
public:
  //! \brief Constructor.
  AutoReadLock(RdWrLock* rd_lock)
      : mpRdLock(rd_lock)
  {
    ASSERT_C(mpRdLock != NULL);
    mpRdLock->readLock();
  }
  
  //! \brief Default destructor.
  ~AutoReadLock() {
    mpRdLock->unlock();
  }

protected:
  // None...

private:
  RdWrLock* mpRdLock;             //!< Read lock.
  
  //! \brief Default constructor.
  AutoReadLock();

};



/*!
 * \class AutoWriteLock
 * \brief Automatically lock for reading.
 */
class AutoWriteLock
{
public:
  //! \brief Constructor.
  AutoWriteLock(RdWrLock* wr_lock)
      : mpWrLock(wr_lock)
  {
    ASSERT_C(mpWrLock != NULL);
    mpWrLock->writeLock();
  }
  
  //! \brief Default destructor.
  ~AutoWriteLock() {
    mpWrLock->unlock();
  }

protected:
  // None...

private:
  RdWrLock* mpWrLock;             //!< Write lock.
  
  //! \brief Default constructor.
  AutoWriteLock();

};

#endif
